home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / mint / utils / stelm3.lzh / STELM / ELM.C < prev    next >
C/C++ Source or Header  |  1993-12-11  |  20KB  |  857 lines

  1. /* ELM: (c) Jos & Kees Lemmens; Oktober 1993.
  2.  
  3.    This program behaves in a simular way as the UNIX 'elm' program,
  4.    which is very popular among UNIX users. (although it has much less
  5.    functionality !)
  6.    However, the code was written completely by ourselves and we didn't
  7.    need much more !!
  8.    Unfortunately it can only handle local mail, but it is easy to add 
  9.    an external program that can handle uucp mail.
  10.  
  11.    Code runs on ATARI (under MINT), on AMIGA 500-4000 (with gcc) and
  12.    was also tested on several UNIX platforms.
  13.    
  14.    1.4 : cursor keys on Atari console now recognized;
  15.          uucp mailaddresses redirected to OutboudMail function (same
  16.          function as for Internet mail)
  17.  
  18.    Any questions or suggestions about this program can be send to:
  19.    lemmens@dv.twi.tudelft.nl
  20. */
  21.  
  22. /* standard headers */
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>        /* getenv, malloc, free and exit */
  26. #include <string.h>
  27. #include <ctype.h>
  28. #include <time.h>
  29. #include <stdarg.h>
  30.  
  31. #ifdef __MINT__
  32. #include <osbind.h>
  33. #include <termcap.h>
  34. #include <ioctl.h>        /* ioctl & tty structs */
  35. #include <fcntl.h>        /* O_RDONLY (access) */
  36. #else
  37. #include <curses.h>
  38. #include <term.h>
  39. #include <termios.h>
  40. #include <sys/wait.h>
  41. #endif
  42.  
  43. /* UNIX headers */
  44.  
  45. #include <signal.h>        /* only for suspend routine */
  46. #include <unistd.h>
  47.  
  48. /* special headers */
  49.  
  50. #include "elm.h"
  51.  
  52. static char *version = "[ELM ST, J&KL; v1.4]";
  53.  
  54. /* termcap variables */
  55.  
  56. static char *_tcpent,*_tcpbuf;
  57. static char *CL,*CM,*SO,*SE,*CE,*ME,*MR;
  58. static int LINES,COLS;
  59.  
  60. #ifdef __MINT__
  61. struct ltchars ltold,ltnew;    /* disable suspend */
  62.  
  63. void ttraw(struct ltchars *ltold,struct ltchars *ltnew)
  64. {
  65.     if(ioctl(0, TIOCGLTC, (char *) ltold) < 0)
  66.         puts("Can't do ioctl");
  67.     ioctl(0, TIOCGLTC, (char *)ltnew);
  68.  
  69.     ltnew->t_suspc = ltnew->t_dsuspc = 0xFF;
  70.     ioctl(0, TIOCSLTC, (char *) ltnew);
  71. }
  72.  
  73. void ttcooked(struct ltchars *ltold)
  74. {
  75.     ioctl(0, TIOCSLTC, (char *) ltold);
  76. }
  77. #endif
  78.  
  79. void InitTermcap(void)
  80. {    char *tmp;
  81.  
  82.     if((tmp=getenv("TERM")) != NULL)    /* use UNIX termcap */
  83.     {    _tcpent = (char *)malloc(2048); /* must be enough ! */
  84.         tgetent(_tcpent,tmp);
  85.         _tcpbuf = _tcpent +1024;
  86.  
  87.         CL = tgetstr("cl", &_tcpbuf);    CM = tgetstr("cm", &_tcpbuf);
  88.         SO = tgetstr("so", &_tcpbuf);    SE = tgetstr("se", &_tcpbuf);
  89.         CE = tgetstr("ce", &_tcpbuf);    ME = tgetstr("me", &_tcpbuf);
  90.         MR = tgetstr("mr", &_tcpbuf);
  91.  
  92.         if((tmp=getenv("LINES")) == NULL)
  93.             LINES = tgetnum("li");
  94.         else
  95.             LINES = atoi(tmp);
  96.  
  97.         if((tmp=getenv("COLUMNS")) == NULL)
  98.             COLS = tgetnum("co");
  99.         else
  100.             COLS  = atoi(tmp);
  101.     }
  102.     else            /* set acceptable defaults : VT52 code */
  103.     {    CL = "\33H\33J";    CM = "\33Y%+ %+ ";
  104.         SO = "\33p";        SE = "\33q";
  105.         CE = "\33K";
  106.         LINES = 24;        COLS = 80;
  107.     }
  108. }
  109.  
  110. #ifdef __hpux    /* stupid error in HPUX 9.01 headerfile */
  111. int outc(char c)
  112. #else
  113. int outc(int c)
  114. #endif
  115. {    return putchar(c);
  116. }
  117.  
  118. void Clrscr(void)
  119. {    tputs(CL,1,outc);
  120. }
  121.  
  122. void Clrtoeol(void)
  123. {    tputs(CE,1,outc);
  124. }
  125.  
  126. void Gotoxy(int x,int y)
  127. {    tputs(tgoto(CM, x, y),1,outc);
  128. }
  129.  
  130. void EndTermcap(void)
  131. {    free(_tcpent);
  132. }
  133.  
  134. void PutStr (char *string,...)
  135. {    va_list ptr;
  136.  
  137.      if(string == NULL)
  138.         return;
  139.  
  140.     va_start(ptr,string);
  141.     vfprintf(stdout,string,ptr);
  142.     fflush(stdout);
  143.     va_end(ptr);
  144. }
  145.  
  146. char GetChar(void)
  147. {    char c;
  148.  
  149. #ifdef __MINT__
  150.     /* this fixes for ATARI cursor keys using scancodes */
  151.     static union { long scan; char byte[4]; } ch;
  152.  
  153.     ch.scan=Crawcin();
  154.     if (ch.byte[3] == 0)
  155.     switch(ch.byte[1])
  156.     {    case 'H': return 'k'; /* cursor up */
  157.         case 'P': return 'j'; /* cursor down */ 
  158. /*        case 'K': return 'h'; /* cursor left */
  159. /*        case 'M': return 'l'; /* cursor right */
  160.     }
  161.  
  162.     c = ch.byte[3];
  163. #else
  164. #ifdef __AMIGA__    /* doesn't echo for some reason */
  165.     read(fileno(stdin),&c,1);
  166.     write(fileno(stdout),&c,1);
  167. #else
  168.     read(fileno(stdin),&c,1);
  169. #endif
  170. #endif
  171.     return c;
  172. }
  173.  
  174. char *GetStr(char *string,int size)
  175. {
  176. #ifdef __AMIGA__
  177. /* this implies that input editing (backspacing) is not possible ! */
  178.     int count=0;
  179.     do
  180.     {    *string = GetChar();
  181.         if(*string == '\r')
  182.         {    *string = '\0';
  183.             break;
  184.         }
  185.     }    while(string++,count++ < size);
  186. #else
  187.     fgets(string,size,stdin);
  188. #endif
  189.  
  190. /* todo: try fflush(stdin) on AMIGA, maybe this works !! */
  191.  
  192.     return string;
  193. }
  194.  
  195. void usage(void)
  196. {    fputs("\nUsage: elm [-f <mailfile>] [-e <editor>]\n",stderr);
  197.     exit(1);
  198. }
  199.  
  200. void PutStatus(char *string,...)
  201. {    va_list ptr;
  202.  
  203.     va_start(ptr,string);
  204.     Gotoxy(0,LINES-2);
  205.     Clrtoeol();
  206.     vfprintf(stdout,string,ptr);
  207.     fflush(stdout);
  208.     va_end(ptr);
  209. }
  210.  
  211. void PutHeader(Mbox *M)
  212. {    Gotoxy(5,STARTHEADER);
  213.     PutStr("Mailbox '%.30s' with %d messages %s",M->Path,M->Count,version);
  214. }
  215.  
  216. void PutMenus(void)
  217. {
  218.     Gotoxy(4,STARTMENU);
  219.     PutStr("m)ail user; f)orward user; r)eply user; $ = reread mailfile; q)uit");
  220.     Gotoxy(3,STARTMENU+1);
  221.     PutStr("k = move up; j = move down; s)ave to file; d)elete mail; u)ndelete mail");
  222.     Gotoxy(4,STARTMENU+2);
  223.     PutStr("! = start shell;  To read a message, press RETURN");
  224. }
  225.  
  226. void PutMessage(Mbox *M,int x)
  227. {    int offset = 0;
  228.  
  229.     offset = M->CurMsg /(MSGLISTSIZE) * MSGLISTSIZE;
  230.  
  231.     Gotoxy(0,x-offset+STARTLIST);
  232.  
  233.     PutStr ("   %1.1s %.3d  %-6.6s  %-15.15s  (%.3d)  %-35.35s",
  234.         &M->Msglist[x]->flag,    x+1,
  235.         M->Msglist[x]->date + 4,
  236.         M->Msglist[x]->sender,
  237.         M->Msglist[x]->nrlines,
  238.         M->Msglist[x]->subject);
  239. }
  240.  
  241. void PutMessages(Mbox *M)
  242. {    int x;
  243.     int offset = 0;
  244.  
  245.     offset = M->CurMsg /(MSGLISTSIZE) * MSGLISTSIZE;
  246.  
  247.     for(x=0;x<MSGLISTSIZE && x+offset<M->Count; x++)
  248.         PutMessage(M,offset+x);
  249.  
  250.     while(x<MSGLISTSIZE)
  251.     {    Gotoxy(0,x+STARTLIST);
  252.         Clrtoeol();
  253.         x++;
  254.     }
  255. }
  256.  
  257. void OpenMailbox(Mbox *M)
  258. {    if((M->fd = fopen (ux2dos(M->Path), "r")) == NULL)
  259.     {    /* create an empty mailfile */
  260.         if((M->fd = fopen (ux2dos(M->Path), "w+")) == NULL)
  261.         {    fprintf(stderr,"Can't open mailbox for %s\n",M->User);
  262.             exit(1);
  263.         }
  264.         else
  265.         {    PutStatus("Empty mailbox %s created; Press a key ...",
  266.                 M->Path);
  267.             GetChar();
  268.         }
  269.     }
  270. }
  271.  
  272. void CloseMailbox(Mbox *M)
  273. {    fclose(M->fd);
  274. }
  275.  
  276. void RemoveCR(char *ptr)
  277. {    char *tmp;
  278.  
  279.     if((tmp=strchr(ptr,'\n')) != NULL) *tmp = 0;
  280. }
  281.  
  282. char *EatWhiteSpace(char *ptr)
  283. {    while(*ptr == ' ' || *ptr == '\t') ptr++;
  284.     return ptr;
  285. }
  286.  
  287. void BuildMailList(Mbox *M)
  288. {    int x;
  289.     int nrlines=0;
  290.     char regel[MAXSTR+1], *tmp1,*tmp2;
  291.     
  292.     OpenMailbox(M);
  293.  
  294.     for(x=0;x < MAXMSG && !feof(M->fd);x++ )
  295.     {
  296.         /* first search for start of (next) message */
  297.         while (strncmp (regel, "From ", 5) && !feof(M->fd) )
  298.         {    fgets(regel,MAXSTR,M->fd);
  299.             nrlines++;
  300.         }
  301.  
  302.         if(feof(M->fd)) break;
  303.  
  304.         M->Msglist[x] = calloc(1,sizeof(Msg));
  305.         M->Msglist[x]->start  = ftell(M->fd) - strlen(regel) - 1;
  306.         M->Msglist[x]->flag   = 'N';
  307.         M->Msglist[x]->status = 0;
  308.         /* assume new msg until proved to be old */
  309.  
  310.         if(x>0) M->Msglist[x-1]->nrlines = nrlines;
  311.  
  312.         nrlines=0;    /* start new line count */
  313.  
  314.         if((tmp1 = strchr (regel, ' ')) != NULL)    /* sender */
  315.         {    tmp1 = EatWhiteSpace(tmp1);
  316.  
  317.             if((tmp2 = strchr (tmp1, ' ')) != NULL)    /* date */
  318.             {    *tmp2++ = 0;                /* fix end of tmp1 */
  319.                 tmp2 = EatWhiteSpace(tmp2);
  320.                 strncpy(M->Msglist[x]->date,tmp2,MAXDATE);
  321.             }
  322.             strncpy(M->Msglist[x]->sender,tmp1,MAXNAME);
  323.         }
  324.         do
  325.         {    fgets (regel,MAXSTR,M->fd);
  326.             nrlines++;
  327.  
  328.             if(!strncmp (regel, "Status:",7))
  329.             {    if(strchr(regel + 7,'R') != NULL)
  330.                     M->Msglist[x]->flag = ' ';
  331.                 M->Msglist[x]->status = 1;
  332.             }
  333.             else if(!strncmp (regel, "Subject:",8))
  334.             {    tmp1 = EatWhiteSpace(regel + 8);
  335.                 RemoveCR(tmp1);
  336.                 strncpy(M->Msglist[x]->subject,tmp1,MAXSUBJECT);
  337.             }
  338.         }while (strncmp (regel, "From ", 5) && !feof(M->fd) );
  339.     }
  340.  
  341.     if(x>0) M->Msglist[x-1]->nrlines = nrlines;    /* save length for last message */
  342.  
  343.     /* last (extra) record is only used save end of file position */
  344.  
  345.     M->Msglist[x] = calloc(1,sizeof(Msg));
  346.     M->Msglist[x]->start = ftell(M->fd);
  347.  
  348.     if(x == 0)    /* fix for empty file */
  349.     {    M->Msglist[1] = calloc(1,sizeof(Msg));
  350.         M->Msglist[1]->start = ftell(M->fd);
  351.     }
  352.  
  353.     M->Count = x;
  354.     M->CurMsg = 0;
  355.     CloseMailbox(M);
  356. }
  357.  
  358. void SetCurMsg(Mbox *M,int new,int echo)